<?php

/* PHP [extended] Data Objects, aka PeDO (pun intended)
MBMBMBMBMBMBMBMBMBBBMBEXXMBBMBMBMBMBMBMMMBMBMBMBMBMBMMMBMMMBMMMBMBMBMBMBMBMBMBMB
BMBMBMBMBMBMBMBMBMB1:       .rRMBBBMBMBBBBBMBMBMBMBMBMBBBMBMBMBMBMBMBBBBBMBMBMBB
MBMBMBBBBBBBMBMBBr    .::,.    .MBBBMBMBMBMBBBMBMBMBBBMBMBBBMBMBBBMBMBMBMBMBMBMB
BBBMBMBBBMBMBMBO   :;;;:::;;i:   MBMBBBMBMBBBMBMBMBBBMBMBMBMBMBMBMBMBMBMBBBMBMBM
MBMBMBMBBBMBMBW  :;;,       .;;. .MBMBMBMBMBMBMBMBBBMBMBBBMBBBEJ7LuGMBMBMBMBMBMB
BMBMBBBMBMBMBM  :;;   ,ic;:   ;;  cMBMBMBMBMBBBMBBBMBBBMBMBX:        .OMBBBBBMBM
MBMBMBMBMBMBMZ  ;;. .KRRORMM: .;:  EO2i:.  . .;7L1DMMBBBMR.   .:;;::   ;MBMBMBMB
BMBMBMBMBMBMB: .;:  MOXSH0RMB. ,i,                    RM;   ;;i:.   ,:  rBBMBMBM
MBBBMBMBBBBBM. :;, rRXFZOWx:   :::,.,::::::::::;;;:,      :r;:        :  RMBMBMB
BMBMBMBBBMBMB. :;. 7R0RZ;    .;:::;::::::,::;;iirirr7r;,.   ,  .x0ORO; . .BMBMBM
MBMBMBMBMBMBM. :;, LMRr    ::;::::::::::,::iii;i;i;i;ii77r.   JBMDXKEB;.  MBMBMB
MMBMBMBMBMBMB, ,;: :W.  .:;::::::::::::,:;i;i;;;;;;;;;i;irci. .SM0SUSM3   BMBMBM
MBMBMBMBBBBBML  :;    .;:::::::::::::::;ii;i;;;;;;;;;;;;;;;77:  ;R0H0R,. .BBBBBB
BMBMBMBMBMBMBM  ,;i. ,;::::::::::::,::;ii;;;;;;;;;i;;;;;;;;;irr  .WRR: . LBMBMBM
MBMBMBMBBBBBMBG  :..:::::::::::::::::;ii;;;i;;;;;;;;;;;;;;;;;ir7. .Mi :  BMBMBMB
BMBBBMBBBMBMBMBR   .;:::::::::::::::;;;;;;;;;;i;i;;;;;;;;;;;;;iic.   :  BMBMBMBM
MBMBMBMBMBMBMBMB  ,;::::::::::::::,:;i;;;;;;;;;;;;;i;;;;;;;;;;;irv  .  DMBMBMBMB
BBBMBMBMBMBMBBB  ,;::::::::::::::::;i;;;;;;;;;;;;;i;;;;;;;;;i;;;irr   WMBBBMBMBM
MBBBMBMBMBMBMBi  ;:::::::::::::;:;icri;;;;;;;;;;;i;;;i;;;;;;;;;;;i7, SMBMBMBMBMB
BMBMBMBMBMBMBM  ;::::::::::::::.   .iri;i;;;;;;;;;i;;;;;;;;;i;;;;;rr :BMBMBMBMBM
MBMBMBMBMBMBM: ,::::::::::::::       :ri;;;i;;;;;i;;;;;;;i;rr7ri;i;7  MBMBMBMBBM
BMBMBBBBBMBMB  :::::::::::::;         ;ri;;;;;;;;;i;;;i;;i7i;:ir7;ii: LBBBBMBMBM
MBMBMBMBMBMBL .;:::::::::::::         .7;i;i;;;;;;;;;;;irr.    .;7irr ,BMBMBBBMB
BBBMBMBMBMBM  :::::::::::::::         .7;;i;;;;;;;i;;;iir        :7;7  MBMBMBMBM
MBMBBBMBMBMD  :::::::::::::::         :7;i;;;;;;;;;;;i;7.         rir, OMBMBMBMB
MMBBBMBBBMBr  ;:::::::::::::::       :7;;;;;;;;;;;i;;;ir.         ri7: XBBBBBBBM
MBMBMBMBBBM: ::::::::::::::::::, . ,;7ii;;;;;;;;;;;;;i;7.         rir; SMBMBBBMB
BMBMBMBBBMB  :::::::::::::::::::;7c7r;;:::::::;:;:;;;;iri        :7;r: 2BMBMBBBM
MBMBMBMBMBR  ;:::::::::::::::::::;r7;;:::::;;iii:::::;:irr      :7;;ii cBBMBMBBB
BMBBBMBMBM7 .::::::::::::::::::::::  :XFSUSPRRRDWPu7;:::rv7;::;r7i;;ii rBBBMBMBM
MBBBBBMBMB  :::::::::::::::::::::   rPZPHPZR3:  .cWRHU1; :rvr7rr;;;;;r ;MBMBMBMB
BMBMBBBMBP  ;:::::::::::::::::::  ;RRHS1SSG,       1WHWL   ir;;;;;;;ir ,BMBMBMBM
MBBBMBMBM  ::::::::::::::::::::. :REUF1F20S        :EHFZOL  rr;i;;;;;7  MBMBMBMB
MMBMBMBMr .:::::::::::::::::::;  DOUU2U1FSD.       7DUUFZM; :ri;;;;;;r. BMBMBMBM
MBMBMBM3  :::::::::::::::::::::  RDS1U1F1SEZ      rDSU1FSM3 ,7;;;i;i;r: DBMBMBMB
BMBMBMD  :::::::::::::::::::::;  ;BOEXPPGDRMBx::LEBPS1F1PM7 :ri;;;;;;ii 7BBMBMBM
MBMBBB  :;::::::::::::::::::::::  :SGOGESv:..  ,70OREKHGMS  ir;;;;;;;ir  BMBMBBB
BMBMB  :;:,,:::::::::::::::::::::.          .::    :1DMXi  :7;;;;;i;i;7. LBMBMBM
MBBB       ::::::::::::::::::::::;:.  ,  2MBMBBBRu    .   ;r;i;i;;;;;ii7  MBMBMB
BMS   :R; ::::::::::::::::::::::::;: .U, GBDDEDDRMBi   .;rr;;;;;r;i;i;rc; ;MBMBM
MBOJUBMR .;;:::::::::::::::::::::::: .J. ZBGK0PEGB1i  icri;i;i;;:riir:  .  .FBMB
BMBMBMB  ;;:,:::::::::::::::::::::::  J: 7BGZPZ0MRr:  vi;;iii;7:  7i7  .     MBM
MBMBMBF .i.  ;;, ::;:,:::::::::::::;  v7  OBWDDBR.:. :r;;r:.i7c,  :Lr ;BMBxSMBMB
BMBMBM;     :;,  ,r.  :;..::::::::::. iL;  SBMBR  7  ir;;r: :x:   ,u, EMBMBMBMBM
MBMBMB. c   .    ,:    :  :::::::::::  Lc;  .:,  v: .7;;;r: ,;  :. i  JBMBBBMBMB
BMBMBMBMK     ::    i.  .::::::::,::i: .LL7.   ,s7  rii;;ir    :r.     ,BMBBBMBM
MBBBMBM; .:;:;;;.  ;;:.,:::::::::::iiv.  i7JLssJ;  ;r;;;;i7.  :;::.,;L,  RMBBBMM
BMBBBM.  :::::::;:::::;::::::,:::;i;ii7:   .:::   ;ri;;;;;r;.:;:::r7ri7;  3MBMBM
MBBBM7  ::::::::::::::::::::,::;;i;;;;i7r:      ,rri;;;;;iii,:::::;i;;;rr  cMBMB
BMBMO  ::::::::::::::::::::,::;;;;;;;;i;rr7rr;rr7i;;;;;;;;r: ::::,:ii;i;rr  cMBM
 * Copyright (C) 2011 by Shanshui Liu <me@lx.sg>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
*/

class PeDO extends PDO {
	// Default fetch mode
	public $fetchMode = parent::FETCH_ASSOC;
	
	/**
	 * PeDO constructor with custom attributes set
	 * @param string $dsn Data source name
	 * @param string $username Data source username
	 * @param string $password Data source password
	 * @param array $options Additional options to be used
	 */
	public function __construct($dsn, $username = null, $password = null, $options = null) {
		parent::__construct($dsn, $username, $password, $options);
		$this->setAttribute(parent::ATTR_ERRMODE, parent::ERRMODE_EXCEPTION);
	}
	
	/**
	 * PeDO factory for MySQL connections
	 * @param string $server MySQL server hostname[:port]
	 * @param string $username Username
	 * @param string $password User password
	 * @param string $database Database name
	 * @param array $options Additional options to be used
	 */
	public static function mysql($server, $username, $password, $database, $options = null) {
		return new self('mysql:host=' . $server . ';dbname=' . $database, $username, $password, $options);
	}
	
	/**
	 * Prepares and executes a query and returns all the result rows (SELECT) or the number of rows affected (INSERT, UPDATE, DELETE etc.)
	 * @param string $query SQL query to execute
	 * @param mixed ... Values to be passed to the prepared statement
	 * @return array Array of result rows for SELECT statements, integer indicating number of rows affected otherwise
	 */
	public function q($query) {
		$args = func_get_args();
		$ps = call_user_func_array(array($this, 'px'), $args);
		return stripos(trim($query), 'SELECT') === 0 ? $ps->fetchAll() : $ps->rowCount();
	}
	
	/**
	 * Prepares and executes a query and returns the first result row
	 * @param string $query SQL query to execute
	 * @param mixed ... Values to be passed to the prepared statement
	 * @return array The first result row as an associative array or FALSE if there is no result row
	 */
	public function qr($query) {
		$args = func_get_args();
		return call_user_func_array(array($this, 'px'), $args)->fetch();
	}
	
	/**
	 * Prepares and executes a query and returns the first column of all result rows
	 * @param string $query SQL query to execute
	 * @param mixed ... Values to be passed to the prepared statement
	 * @return array Array of values in the first column
	 */
	public function qc($query) {
		$args = func_get_args();
		return call_user_func_array(array($this, 'px'), $args)->fetchAll(PDO::FETCH_COLUMN, 0);
	}
	
	/**
	 * Prepares and executes a query and returns the first value (first column of the first row)
	 * @param string $query SQL query to execute
	 * @param mixed ... Values to be passed to the prepared statement
	 * @return mixed First value of the result or FALSE if there is no result row
	 */
	public function q1($query) {
		$args = func_get_args();
		return call_user_func_array(array($this, 'px'), $args)->fetchColumn();
	}
	
	/**
	 * Prepares and executes a query and returns a PDOStatement object
	 * @param string $query SQL query to execute
	 * @param mixed ... Values to be passed to the prepared statement
	 * @return PDOStatement Object representing the executed query
	 */
	public function px($query) {
		$args = func_get_args();
		$statement = $this->prepare($query);
		$statement->execute(array_slice($args, 1));
		$statement->setFetchMode($this->fetchMode);
		return $statement;
	}
	
	public function write($table, $data, $where = array()) {
		$args[] = $where ?
			"UPDATE $table SET " . implode(' = ?, ', array_keys($data)) . ' = ? WHERE ' . implode(' = ?, ', array_keys($where)) . ' = ?' :
			"INSERT INTO $table(" . implode(',', array_keys($data)) . ') VALUES(' . str_repeat('?, ', count($data) - 1) . '?)';
		foreach ($data as $d) $args[] = $d;
		foreach ($where as $w) $args[] = $w;
		return call_user_func_array(array($this, 'q'), $args);
	}
}

?>